package gestordeentidades.persistance;

import gestordeentidades.persistance.interfaces.IGateway;
import gestordeentidades.identitymap.interfaces.IEntityMap;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import gestordeentidades.persistance.interfaces.IDataBaseAdapter;
import gestordeentidades.persistance.interfaces.IPersistance;

/**
 * Trabalho DAS - 2014/2015
 * @author a21210380, a21190325, a21210392
 */
public class Persistance implements IPersistance {
    
    private static final Logger logger = Logger.getLogger(Persistance.class.getName());
    
    private final Map<Class, IGateway> gateways =  new HashMap<>();
    private final IDataBaseAdapter dataBase;
    
    public Persistance(IDataBaseAdapter dataBase) {
        this.dataBase = dataBase;
    }
    
    /**
     * Dizer à classe que implementa IPersistance que permite inserir/atualizar/apagar 
     * uma classe que extend da classe DataBaseObject e usa o IGateway para trabalhar 
     * com essa classe
     * @param <T> extends DataBaseObject para ter acesso ao id do objecto
     * @param entidade T que vai permitir ser utilizada pelo IGateway
     * @param gateway IGateway que trabalha sobre a entidade T
     * @return Persistance para fazer chain
     */
    public <T extends DataBaseObject> Persistance iniciarEntidade(Class<T> entidade, IGateway<T> gateway) {
        if(entidade == null) {
            throw new NullPointerException("O entidade não pode ser null!");
        }
        if(gateway == null) {
            throw new NullPointerException("O gateway não pode ser null!");
        }
        if(gateways.containsKey(entidade)) {
            logger.logp(Level.WARNING, Persistance.class.getName(), "iniciarEntidade()", "A entidade " + entidade + " já se encontra inicializada!");
            return this;
        }
        gateways.put(entidade, gateway);
        gateway.initTable(dataBase);
        return this;
    }
    
    @Override
    public <T extends DataBaseObject> boolean inserirNovaEntidade(T object) {
        if(object == null) {
            throw new NullPointerException("O object não pode ser null!");
        }
        if(gateways.containsKey(object.getClass())) {
            return gateways.get(object.getClass()).inserirNovaEntidade(dataBase, object);
        } else {
            logger.logp(Level.WARNING, Persistance.class.getName(), "inserirNovaEntidade()", "A entidade " + object.getClass() + " não está inicializada!");
            return false;
        }
    }

    @Override
    public <T extends DataBaseObject> boolean atualizarEntidade(T object) {
        if(object == null) {
            throw new NullPointerException("O object não pode ser null!");
        }
        if(gateways.containsKey(object.getClass())) {
            return gateways.get(object.getClass()).atualizarEntidade(dataBase, object);
        } else {
            logger.logp(Level.WARNING, Persistance.class.getName(), "atualizarEntidade()", "A entidade " + object.getClass() + " não está inicializada!");
            return false;
        }
    }
    
    @Override
    public <T extends DataBaseObject> boolean apagarEntidade(T object) {
        if(object == null) {
            throw new NullPointerException("O object não pode ser null!");
        }
        if(gateways.containsKey(object.getClass())) {
            return gateways.get(object.getClass()).apagarEntidade(dataBase, object);
        } else {
            logger.logp(Level.WARNING, Persistance.class.getName(), "apagarEntidade()", "A entidade " + object.getClass() + " não está inicializada!");
            return false;
        }
    }
    
    @Override
    public <T extends DataBaseObject> T procurarEntidadePeloID(Class<T> c, IEntityMap entityMap, int id) {
        if(gateways.containsKey(c)) {
            return (T) gateways.get(c).procurarEntidadePeloID(dataBase, entityMap, id);
        } else {
            logger.logp(Level.WARNING, Persistance.class.getName(), "procurarEntidadePeloID()", "A entidade " + c + " não está inicializada!");
            return null;
        }
    }
    
    @Override
    public <T extends DataBaseObject> Map<Integer, T> procurarPorTodasAsEntidadesComoMapa(Class<T> entidade, IEntityMap entityMap) {
        if(gateways.containsKey(entidade)) {
            return gateways.get(entidade).procurarPorTodasAsEntidadesComoMapa(dataBase, entityMap);
        } else {
            logger.logp(Level.WARNING, Persistance.class.getName(), "procurarPorTodasAsEntidadesComoMapa()", "A entidade " + entidade + " não está inicializada!");
            return null;
        }
    }

    @Override
    public <T extends DataBaseObject> IGateway<T> getGateway(Class<T> entidade) {
        if(gateways.containsKey(entidade)) {
            return gateways.get(entidade);
        } else {
            logger.logp(Level.WARNING, Persistance.class.getName(), "getGateway()", "A entidade " + entidade + " não está inicializada!");
            return null;
        }
    } 
}
